#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

class Connection;
class TcpServer;

using func_t = std::function<void(Connection *)>;

class Connection
{
public:
    Connection(int sockfd, uint32_t events, TcpServer *R)
        : _sockfd(sockfd), _events(events), _R(R)
    {
    }
    void RegisterCallback(func_t recver, func_t sender, func_t excepter)
    {
        _recver = recver;
        _sender = sender;
        _excepter = excepter;
    }
    void AddInBuffer(std::string buffer)
    {
        _inbuffer += buffer; // 追加到inbuffer中
    }
    void AddOutBuffer(const std::string &buffer)
    {
        _outbuffer += buffer;
    }
    bool OutBufferEmpty()
    {
        return _outbuffer.empty();
    }
    int SockFd()
    {
        return _sockfd;
    }
    uint32_t Events()
    {
        return _events;
    }
    void SetEvents(uint32_t events)
    {
        _events = events;
    }
    void SetClient(const struct sockaddr_in c)
    {
        _client = c;
    }
    std::string &InBuffer()
    {
        return _inbuffer;
    }
    std::string &OutBuffer()
    {
        return _outbuffer;
    }
    void Close()
    {
        ::close(_sockfd);
    }
    ~Connection()
    {
    }

private:
    // 对应的sockfd
    int _sockfd;
    // 对应的缓冲区
    std::string _inbuffer;  // _sockfd 接受缓冲区, 暂时用string代替
    std::string _outbuffer; // _sockfd 发送缓冲区

    // 关心的事件
    uint32_t _events;
    // 维护一下client的ip和port信息
    struct sockaddr_in _client;

public:
    // 对特定connection进行处理的回调函数
    func_t _recver;
    func_t _sender;
    func_t _excepter;
    // TcpServer的回指指针 - TODO
    TcpServer *_R;
};

class ConnectionFactory
{
public:
    static Connection *BuildListenConnection(int listensock, func_t recver, uint32_t events, TcpServer *R)
    {
        Connection *conn = new Connection(listensock, events, R);
        conn->RegisterCallback(recver, nullptr, nullptr);
        return conn;
    }
    static Connection *BuildNormalConnection(int sockfd,
                                             func_t recver,
                                             func_t sender,
                                             func_t excepter,
                                             uint32_t events,
                                             TcpServer *R)
    {
        Connection *conn = new Connection(sockfd, events, R);
        conn->RegisterCallback(recver, sender, excepter);
        return conn;
    }
};
